package com.example.common.security.service;


import cn.hutool.core.lang.UUID;
import com.example.common.core.constants.CacheConstants;
import com.example.common.core.constants.JWTConstants;
import com.example.common.core.domain.LoginUser;
import com.example.common.core.utils.JwtUtils;
import com.example.redis.service.RedisService;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
public class TokenService {

    @Autowired
    private RedisService redisService;
    //生成令牌
    public String createToken(String secret,Integer indentity,Long userId,String nickName,String headImage){
        //1.生成令牌
        //(1).构造claim数据体
        //a.使用hutool的UUDI工具，生成用户唯一标识userKey
        String userKey = UUID.fastUUID().toString();
        //b.获取userId
        //传参过来了
        //c.创建claim并存入数据
        HashMap<String ,Object> claim = new HashMap<>();
        claim.put(JWTConstants.USER_KEY,userKey);
        claim.put(JWTConstants.USER_ID,userId);
        //(2).获取secret生成
        //配置文件设置，传参过来了
        //(3).调用JWT方法生成令牌
        String token = JwtUtils.createToken(claim,secret);
        //2.缓存敏感信息
        LoginUser loginUser = new LoginUser();
        loginUser.setIdentity(indentity);
        loginUser.setNickName(nickName);
        loginUser.setHeadImage(headImage);
        redisLoginUser(userKey,loginUser);
        return token;
    }

    //延长过期时间
    public void extendToken(Claims claims){
        String userKey = getUserKey(claims);
        if (userKey == null){
            return;
        }
        String tokenKey = getTokenKey(userKey);
        //获取当前key的过期时间
        Long expire = redisService.getExpire(tokenKey,TimeUnit.MINUTES);
        //如果小于某个值，才延长
        if (expire != null && expire < CacheConstants.REFRESH_TIME){
            redisService.expire(tokenKey,CacheConstants.LOGIN_TOKEN_KEY_EXP,TimeUnit.MINUTES);
        }
    }

    //根据令牌从redis中获取用户信息
    public LoginUser getLoginUser(String token,String secret) {
        Claims claims = getClaims(token,secret);
        String userKey = getUserKey(claims);
        if (userKey == null){
            return null;
        }
        return redisService.getCacheObject(getTokenKey(userKey), LoginUser.class);
    }

    //把令牌中的userKey解析出来
    public String getUserKey(Claims claims) {
        //解析令牌
        String userKey = JwtUtils.getUserKey(claims);
        return userKey;
    }

    //从claims中获取userId
    public Long getUserId(Claims claims) {
        String userId = JwtUtils.getUserId(claims);
        return Long.valueOf(userId);
    }

    //根据token和secret 解析出jwt数据体claim
    public Claims getClaims(String token,String secret) {
        Claims claims;
        try {
            claims = JwtUtils.parseToken(token,secret);
            if (claims == null){
                //令牌都解析失败了
                log.error("解析令牌token {},出现异常",token);
                throw new RuntimeException("解析令牌token {},出现异常");
            }
        }catch (Exception e){
            //令牌都解析失败了
            log.error("解析令牌token {},出现异常",token,e);
            throw new RuntimeException("解析令牌token {},出现异常");
        }
        return claims;
    }


    //添加敏感信息到缓存
    public void redisLoginUser(String userKey ,LoginUser loginUser){
        //(1).设置key
        //login_tokens:userKey
        //(2).设置value
        //(3).用字符串的形式的保存到redis，因为之前设置了序列化和反序列化,并设置过期时间
        //存入redis
        redisService.setCacheObject(getTokenKey(userKey),loginUser,CacheConstants.LOGIN_TOKEN_KEY_EXP, TimeUnit.MINUTES);
    }

    //删除敏感信息
    public boolean deleteLoginUser(String token, String secret) {
        Claims claims = getClaims(token,secret);
        String userKey = getUserKey(claims);
        if (userKey == null){
            return false;
        }
        return redisService.deleteObject(getTokenKey(userKey));
    }

    //更新用户敏感信息
    public void refreshLoginUser(String nickName, String headImage, String userKey) {
        String tokenKey = getTokenKey(userKey);
        LoginUser loginUser = redisService.getCacheObject(tokenKey, LoginUser.class);
        loginUser.setNickName(nickName);
        loginUser.setHeadImage(headImage);
        redisService.setCacheObject(tokenKey, loginUser);
    }

    //生成redis的key
    public String getTokenKey(String userKey){
        return CacheConstants.LOGIN_TOKEN_KEY + userKey;
    }
}
